from msilib.schema import IniLocator
from time import time
import numpy as np
import json
from dataClean import smooth
from transfer import sendFrequenceToUnity, sendPeakTimeToUnity

FREQUENCE = 300

# 一帧数据调用一次
# 一次完整的动作返回一个特征向量
# 特征向量可用于给 evaluate 分析和规范动作的的一致性
class Analyser:
    def __init__(self) -> None:
        self.time = 0
        self.res = [[0, 0] for i in range(16)]  # 特征向量：res[0][0] 0通道最大值，res[0][1] 0通道最大值出现相对时间，res[0 + 8][0] 0通道最小值  res[0 + 8][1] 0通道最小值出现时间
        self.existData = False
        self.bound = None  # bound[0] 平静区上界，bound[1]平静区下界
        with open("config.json") as f:
            self.bound = json.load(f)["bound"]

    def analyse(self, channel):  # 分析一致性用
        count = 0
        for i in range(8):
            if channel[i] < self.bound[0] and channel[i] > self.bound[1]:
                count += 1
            else:
                self.existData = True
            if channel[i] > self.res[i][0]:
                self.res[i][0] = channel[i]
                self.res[i][1] = self.time
            if channel[i] < self.res[i + 8][0]:
                self.res[i + 8][0] = channel[i]
                self.res[i + 8][1] = self.time
        self.time += 1
        if self.existData and count==8:
            self.existData = False
            self.time = 0
            x0 = self.res[0][1]
            ret = [[y, x-x0] for y,x in self.res]
            self.res = [[0, 0] for i in range(16)]
            return ret
        return None



# 实时分析出波峰，并发送给unity3d
class RTPeakAnalyser:
    def __init__(self) -> None:
        self.__reset()
        self.time = 0  # 帧序列
        self.prevTime = 0  # 上一次波峰出现的时间，用来保证两波峰出现的时间不小于10帧
        self.bound = None  # bound[0] 平静区上界，bound[1]平静区下界
        with open("config.json") as f:
            self.bound = json.load(f)["bound"]
    
    def __reset(self):
        self.existData = False
        self.next = 0  # 下一个出现峰值的通道id
        self.peakVal = [0 for i in range(8)]  # 目前出现的最大值
        self.peakTime = [0 for i in range(8)]  # 目前出现的最大值对应的时间
        self.peakTimeRes = [-1 for i in range(8)]  # 峰值

    # 一帧调用一次
    # 实时分析出波峰并发送给unity
    def analyse(self, channel, personId):  
        count = 0  # 平静区通道数量
        for i in range(8):
            isMoving = False
            # 判断当前通道是否在平静区，在平静区就认为未在划桨
            if self.bound[0] > channel[i]  and channel[i] > self.bound[1]:
                # 在平静区
                count += 1
            else:
                # 在划桨区
                isMoving = True
                self.existData = True  # true表示进入过划桨区

            if isMoving and self.peakTimeRes[i] == -1 and abs(channel[i]) > self.peakVal[i]:  # 更新峰值及峰值出现时间
                self.peakVal[i] = abs(channel[i])
                self.peakTime[i] = self.time

            if isMoving and self.peakTimeRes[i] == -1  and (self.peakVal[i] - abs(channel[i])) / self.peakVal[i] > 0.2 :  # 下降20%则认定峰值出现
                self.peakTimeRes[i] = max(self.peakTime[i], self.prevTime + 10)
                self.prevTime = self.peakTimeRes[i]

                # 将峰值信息发送给unity
                data = [self.peakTimeRes[i] / 100, personId, self.next]
                # data = [peakTimeRes[i], personId, next]
                sendToUnity(data)
                print(data, ' ', self.peakVal[i], '  ', i)
                
                self.next = self.next + 1

        self.time += 1
        if self.existData and count == 8:  # 8个通道都已离开划桨区，进入平静区
            print("***************** 动作完成   帧序列：", self.time)
            self.__reset()

# 多人 实时分析出波峰，并发送给unity3d
# 实现时组合了 RTPeakAnalyser
class MultiPersonRTPeakAnalyser:
    def __init__(self, personNum):
        self.personNum = personNum
        self.analysers = [RTPeakAnalyser() for i in range(personNum)]
    
    def analyse(self, channels): # channels是一个 personNum * 8 的数组，channels[i]表示第i个人的这一帧的8个通道的数据
        for i in range(self.personNum):
            self.analysers[i].analyse(channels[i], personId=i)



# 计算出每次动作的开始帧
# actionNum 表示共计算多少个动作
# 返回 长度为actionNum的一维数组actions，actions[i]表示第i个动作的开始帧
class SplitAnalyser:
    def __init__(self, actionNum) -> None:
        self.time = 0  # 帧序列
        self.existData = False
        self.actionIdx = 0
        self.actionNum = actionNum

        self.actions = [0 for i in range(actionNum)]
        
        self.bound = None  # bound[0] 平静区上界，bound[1]平静区下界
        with open("config.json") as f:
            self.bound = json.load(f)["bound"]
    
    def __reset(self):
        self.existData = False
        self.actionIdx = 0
        self.frames = []

    # 一帧调用一次
    # 计算出每个动作的开始帧
    def analyse(self, channel):  
        channel = smooth(channel)
        channleNotInAction = 0
        for i in range(8):
            # 判断当前通道是否在平静区，在平静区就认为未在划桨
            if self.bound[0] > channel[i]  and channel[i] > self.bound[1]:
                # 在平静区
                channleNotInAction += 1
            else:
                # 在划桨区
                self.existData = True  # true表示进入过划桨区

        if self.actions[self.actionIdx] == 0 and self.existData:
            self.actions[self.actionIdx] = self.time

        if self.existData and channleNotInAction == 8:
            self.actionIdx = self.actionIdx + 1
            if self.actionIdx == self.actionNum:  # 已计算出actionNum个动作，则返回
                return self.actions
            self.existData = False

        self.time += 1

        return None


# 实时分析出波峰，并发送给unity3d
class RTPeakAndFrequenceAnalyser:
    def __init__(self) -> None:
        self.__reset()
        self.time = 0  # 帧序列
        self.prevTime = 0  # 上一次波峰出现的时间，用来保证两波峰出现的时间不小于10帧
        self.bound = None  # bound[0] 平静区上界，bound[1]平静区下界
        with open("config.json") as f:
            self.bound = json.load(f)["bound"]
        
        # 用于计算频率
        self.startTime = [] # 记录动作开始时间帧序列
        self.actionIdx = 0 # 当前是第几个动作 从0开始
    
    def __reset(self):
        self.existData = False
        self.existEffectiveData = False
        self.next = 0  # 下一个出现峰值的通道id
        self.peakVal = [0 for i in range(8)]  # 目前出现的最大值
        self.peakTime = [0 for i in range(8)]  # 目前出现的最大值对应的时间
        self.peakTimeRes = [-1 for i in range(8)]  # 峰值

    # 一帧调用一次
    # 实时分析出波峰并发送给unity
    def analyse(self, channel, personId):  
        count = 0  # 平静区通道数量
        for i in range(8):
            isMoving = False
            # 判断当前通道是否在平静区，在平静区就认为未在划桨
            if self.bound[0] > channel[i]  and channel[i] > self.bound[1]:
                # 在平静区
                count += 1
            else:
                # 在划桨区
                isMoving = True
                self.existData = True  # true表示进入过划桨区
                if channel[i] > 4000:
                    self.existEffectiveData = True

            if isMoving and self.peakTimeRes[i] == -1 and abs(channel[i]) > self.peakVal[i]:  # 更新峰值及峰值出现时间
                self.peakVal[i] = abs(channel[i])
                self.peakTime[i] = self.time

            if isMoving and self.peakTimeRes[i] == -1  and (self.peakVal[i] - abs(channel[i])) / self.peakVal[i] > 0.2 :  # 下降20%则认定峰值出现
                self.peakTimeRes[i] = max(self.peakTime[i], self.prevTime + 10)
                self.prevTime = self.peakTimeRes[i]

                # 将峰值信息发送给unity
                data = [self.peakTimeRes[i] / FREQUENCE, personId, self.next]
                # data = [peakTimeRes[i], personId, next]
                sendPeakTimeToUnity(data)
                print(data, ' ', self.peakVal[i], '  ', i)
                
                self.next = self.next + 1


        # 计算频率
        if self.existData and self.actionIdx == len(self.startTime):
            if len(self.startTime) > 0:
                during = (self.time - self.startTime[self.actionIdx - 1]) / FREQUENCE
                sendFrequenceToUnity([self.time / FREQUENCE, personId, 1 / during])
            self.startTime.append(self.time)

        self.time += 1
        if self.existEffectiveData and count == 8:  # 8个通道都已离开划桨区，进入平静区
            print("***************** 动作完成   帧序列：", self.time)
            self.__reset()

            self.actionIdx = self.actionIdx + 1

# 多人 实时分析出波峰，并发送给unity3d
# 实现时组合了 RTPeakAndFrequenceAnalyser
class MultiPersonRTPeakAndFrequenceAnalyser:
    def __init__(self, personNum):
        self.personNum = personNum
        self.analysers = [RTPeakAndFrequenceAnalyser() for i in range(personNum)]
    
    def analyse(self, channels): # channels是一个 personNum * 8 的数组，channels[i]表示第i个人的这一帧的8个通道的数据
        for i in range(self.personNum):
            self.analysers[i].analyse(channels[i], personId=i)